package com.zkthink.ceres.product.service.impl;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.zkthink.context.BaseContextHandler;
import com.zkthink.database.mybatis.conditions.Wraps;
import com.zkthink.ceres.product.dto.LogisticsCostDTO;
import com.zkthink.ceres.product.entity.LogisticsDetail;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;

import com.zkthink.base.service.SuperServiceImpl;
import com.zkthink.ceres.order.dto.OrderProductDTO;
import com.zkthink.ceres.product.converter.LogisticsBeanConverter;
import com.zkthink.ceres.product.dao.LogisticsMapper;
import com.zkthink.ceres.product.dto.LogisticsDetailDTO;
import com.zkthink.ceres.product.dto.LogisticsRegionDTO;
import com.zkthink.ceres.product.entity.Logistics;
import com.zkthink.ceres.product.service.LogisticsDetailService;
import com.zkthink.ceres.product.service.LogisticsService;
import com.zkthink.ceres.product.strategy.ChargeDetailStrategy;
import com.zkthink.ceres.product.strategy.FirstItemChargeDetailStrategy;
import com.zkthink.ceres.product.strategy.FirstWeightChargeDetailStrategy;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 业务实现类 物流设置
 * </p>
 *
 * @author vivi.huang
 * @date 2020-05-08
 */
@Slf4j
@Service
@AllArgsConstructor
public class LogisticsServiceImpl extends SuperServiceImpl<LogisticsMapper, Logistics> implements LogisticsService {

    private LogisticsBeanConverter converter;

    private LogisticsDetailService logisticsDetailService;

    private LogisticsMapper logisticsMapper;

    @Override
    public long calculateTransportationCost(String tenantCode, String provinceOfReceiveAddress, String cityOfReceiveAddress, List<OrderProductDTO> orderProductDTOList) {

        // 获取对应城市的物流方案
        List<LogisticsDetailDTO> logisticsDetailDTOList =
            findLogisticsDetailListOfMappingAddress(tenantCode, provinceOfReceiveAddress, cityOfReceiveAddress);
        List<Logistics> logisticsList = findLogisticsByIdLis(tenantCode,
            logisticsDetailDTOList.stream().map(LogisticsDetailDTO::getLogisticsId).collect(Collectors.toList()));
        Map<Long, Logistics> map =
            logisticsList.stream().collect(Collectors.toMap(Logistics::getId, t -> t, (o1, o2) -> o2));

        // 找出最贵的费用
        Long charge = logisticsDetailDTOList.stream()
            .map(l -> getChargeDetailStrategy(map.get(l.getLogisticsId()).getChargingWay())
                .calculate(orderProductDTOList, l.getChargeDetailDTO())).max((a, b) -> a > b ? 1 : -1).get();

        return charge;
    }

    @Override
    public LogisticsCostDTO getSuitableLogisticsCost(String tenantCode, String provinceOfReceiveAddress, String cityOfReceiveAddress, List<OrderProductDTO> orderProductDTOList) {

        // 获取对应城市的物流方案
        List<LogisticsDetailDTO> logisticsDetailDTOList =
                findLogisticsDetailListOfMappingAddress(tenantCode, provinceOfReceiveAddress, cityOfReceiveAddress);
        List<Logistics> logisticsList = findLogisticsByIdLis(tenantCode,
                logisticsDetailDTOList.stream().map(LogisticsDetailDTO::getLogisticsId).collect(Collectors.toList()));
        Map<Long, Logistics> map =
                logisticsList.stream().collect(Collectors.toMap(Logistics::getId, t -> t, (o1, o2) -> o2));

        // 找出最贵的费用
        try {
            LogisticsCostDTO target = logisticsDetailDTOList.stream().map(l -> {
                if (map.get(l.getLogisticsId()) == null) {
                    LogisticsCostDTO logisticsCostDTO = new LogisticsCostDTO();
                    logisticsCostDTO.setId(l.getLogisticsId());
                    logisticsCostDTO.setName("");
                    logisticsCostDTO.setCost(0L);
                    return logisticsCostDTO;
                } else {
                    long cost = getChargeDetailStrategy(map.get(l.getLogisticsId()).getChargingWay()).calculate(orderProductDTOList, l.getChargeDetailDTO());
                    LogisticsCostDTO logisticsCostDTO = new LogisticsCostDTO();
                    logisticsCostDTO.setId(l.getLogisticsId());
                    logisticsCostDTO.setName(map.get(l.getLogisticsId()).getName());
                    logisticsCostDTO.setCost(cost);
                    return logisticsCostDTO;
                }

            }).max((a, b) -> a.getCost() > b.getCost() ? 1 : -1).get();
            return target;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public void removeLogisticsAndDetail(List<Long> ids) {
        this.removeByIds(ids);
        List<LogisticsDetail> logisticsDetails = logisticsDetailService.list(Wraps.<LogisticsDetail>lbQ().select(LogisticsDetail::getId).in(LogisticsDetail::getLogisticsId, ids));
        logisticsDetailService.removeByIds(logisticsDetails.stream().map(LogisticsDetail::getId).collect(Collectors.toList()));
    }

    private List<Logistics> findLogisticsByIdLis(String tenantCode, List<Long> idList) {
        return this.logisticsMapper.findLogisticsByIdLis(tenantCode, idList);
    }

    /**
     * 查询匹配地址的物流明细
     * 
     * @param provinceOfReceiveAddress
     * @param cityOfReceiveAddress
     * @return
     */
    private List<LogisticsDetailDTO> findLogisticsDetailListOfMappingAddress(String tenantCode, String provinceOfReceiveAddress,
        String cityOfReceiveAddress) {

        List<LogisticsDetailDTO> logisticsDetailDTOList =
                converter.convertToLogisticsDetailDTOList(logisticsDetailService.findLogisticsDetailList(tenantCode));


        return logisticsDetailDTOList.stream()
            .filter(
                f -> isMappingOfAddress(f.getLogisticsRegionDTOList(), provinceOfReceiveAddress, cityOfReceiveAddress))
            .collect(Collectors.toList());
    }

    private boolean isMappingOfAddress(List<LogisticsRegionDTO> logisticsRegionDTOList, String provinceOfReceiveAddress,
        String cityOfReceiveAddress) {
        return logisticsRegionDTOList.stream().anyMatch(region -> {
            if (region.isOnlyProvince()) {
                return provinceOfReceiveAddress.equals(region.getProvince());
            } else if (region.isMunicipality()) {
                return cityOfReceiveAddress.equals(region.getProvince());
            } else {
                return region.getCityList().stream().anyMatch(c -> c.equals(cityOfReceiveAddress));
            }
        });
    }

    /**
     * 获取运费策略
     *
     * @param chargingWay
     * @return
     */
    private ChargeDetailStrategy getChargeDetailStrategy(Integer chargingWay) {
        if (1 == chargingWay) {
            return new FirstItemChargeDetailStrategy();
        }
        return new FirstWeightChargeDetailStrategy();
    }

}
